using System;
using System.Collections;
using System.Collections.Generic;

using log4net;

using GymManager.Exception;
using GymManager.Mechanism;
using GymManager.Persistence.DAO;
using GymManager.Persistence.VO;


namespace GymManager.Business
{
    /// <summary>
    /// Class responsible by providing services regarding modalitites schedule
    /// </summary>
    public class StudentModalityScheduleServices
    {
        // logger instance
        private ILog _logManager = LogManager.GetLogger(typeof(StudentModalityScheduleServices));

        /// <summary>
        /// Method responsible by checking if the max number of students in according to a proposed modality
        /// schedule was reached or not
        /// </summary>
        /// <param name="Int32">modality identifier</param>
        /// <param name="Int32">day of week identifier</param>
        /// <param name="String">time information (hh:mm)</param>
        /// <returns>Flag indicating if the max number of students in class was reached</returns>
        /// <see cref="GymManager.Exception.BusinessException"/>
        public Boolean isMaxNumberOfStudentsInClassReached(Int32 modalityId, Int32 dayOfWeek, String time)
        {
            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("Begin Method");
            }

            Boolean isMaxNumberOfStudentsInClassReached = false;

            try
            {
                // get the number of students
                StudentModalityScheduleDAO modalityScheduleDAO = new StudentModalityScheduleDAO();
                Int32 numberOfStudentsInClass = modalityScheduleDAO.getNumberOfStudentsInClass(modalityId, dayOfWeek, time);

                // get the modality 
                ModalityDAO modalityDAO = new ModalityDAO();
                Modality modalityVO = modalityDAO.findByKey(modalityId);

                // compare if the max number of students was reached
                isMaxNumberOfStudentsInClassReached = (numberOfStudentsInClass == modalityVO.MaxNumberOfStudentsAllowed);
            }
            catch (PersistenceException)
            {
                throw new BusinessException();
            }            
            
            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("End Method");
            }

            return isMaxNumberOfStudentsInClassReached;
        }

        /// <summary>
        /// This method is responsible by returning all students which have classes in a modality
        /// with an associated schedule. The structure will return basically a a dicionary where which key is
        /// a modality whose value is a new dictionary composed by the pair (DAY_OF_WEEK - TIME + List of Students)
        /// </summary>
        /// <returns>
        ///     Schedule structure where each element is:
        ///     key = Modality VO
        ///     value = IDictionary&lt;String, IList&lt;String&gt; &gt;
        ///                         key = string in the following format DayOfWeek-Time
        ///                         value = list of student name
        /// </returns>
        /// <see cref="GymManager.Exception.BusinessException"/>
        public IDictionary<Modality, IDictionary<String, IList<String>>> getStudentsByClass()
        {
            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("Begin Method");
            }

            // structure to be returned
            IDictionary<Modality, IDictionary<String, IList<String>>> processedScheduleIndexedByModality = new Dictionary<Modality, IDictionary<String, IList<String>>>();

            try
            {
                // get all active modalities from database which has an associated schedule
                ModalityDAO modalityDAO = new ModalityDAO();
                IList<Modality> modalityScheduledList = modalityDAO.findAllActiveWithSchedule();

                // infra-structure members used during schedule creation
                Int32 studentClassDayOfWeek = 0; 
                String studentName = String.Empty; 
                String studentClassTime = String.Empty;
                IList<Hashtable> registeredStudentListInModality = null;
                IList<String> modalityStudentList = null;
                IDictionary<String, IList<String>> scheduleDictionary = null;
                String scheduleKey = null;
                
                // dao to get information about an specific modality schedule
                StudentModalityScheduleDAO modalityScheduleDAO = new StudentModalityScheduleDAO();

                foreach (Modality modalityVO in modalityScheduledList)
                {
                    // starting new estructure for this modality
                    scheduleDictionary = new Dictionary<String, IList<String>>();

                    // for each modality, get the students grouped by class (day of week and time)
                    registeredStudentListInModality = modalityScheduleDAO.getStudentScheduleByModality(modalityVO.Id);
                    if (registeredStudentListInModality != null && registeredStudentListInModality.Count > 0)
                    {
                        // for each student analysed, set the correct information about his/her schedule
                        foreach (Hashtable studentEntry in registeredStudentListInModality)
                        {
                            // breaking the information from dictionary structure
                            studentClassDayOfWeek = (Int32)studentEntry["DAY_OF_WEEK"];
                            studentName = (String)studentEntry["NAME"];
                            studentClassTime = (String)studentEntry["TIME"];

                            // check if the day of week has already been processed
                            scheduleKey =  studentClassDayOfWeek + "-" + studentClassTime;
                            if (scheduleDictionary.ContainsKey(scheduleKey))
                            {
                                modalityStudentList = scheduleDictionary[scheduleKey];
                            }
                            else
                            {
                                modalityStudentList = new List<String>();
                                scheduleDictionary[scheduleKey] = modalityStudentList;
                            }

                            // insert the student
                            modalityStudentList.Add(studentName);
                        }
                    }

                    // after this process, associate the processed schedule to the modality
                    processedScheduleIndexedByModality[modalityVO] = scheduleDictionary;
                }
            }
            catch (PersistenceException)
            {
                throw new BusinessException();
            }
            catch (System.Exception ex)
            {
                _logManager.Error("Problems during schedule manipulation", ex);
                throw new BusinessException("Problems during schedule manipulation", ex);
            }


            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("End Method");
            }

            return processedScheduleIndexedByModality;
        }

        /// <summary>
        /// Method responsible by getting all schedule beloging to an specific student modality
        /// </summary>
        /// <param name="Int32">student modality identifier</param>
        /// <returns>IList - list of schedule belonging to an specific student modality</returns>
        /// <see cref="GymManager.Exception.BusinessException"/>
        public IList<StudentModalitySchedule> findByStudentModality(Int32 studentModalityId)
        {
            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("Begin Method");
            }

            IList<StudentModalitySchedule> studentModalityScheduleList = null;

            try
            {
                // get the number of students
                StudentModalityScheduleDAO studentModalityScheduleDAO = new StudentModalityScheduleDAO();
                studentModalityScheduleList = studentModalityScheduleDAO.findByStudentModality(studentModalityId);
            }
            catch (PersistenceException)
            {
                throw new BusinessException();
            }

            if (_logManager.IsInfoEnabled)
            {
                _logManager.Info("End Method");
            }

            return studentModalityScheduleList;
        }
    }
}
